#include "stk_utility.h"
#include <string.h>

void stk_util_replace_all_lws (char *message)
{
    char *tmp;

    if (message == NULL)
    {
        return;
    }

    tmp = message;

    for (; tmp[0] != '\0'; tmp++)
    {
        if (('\0' == tmp[0])
                || ('\0' == tmp[1]) || ('\0' == tmp[2]) || ('\0' == tmp[3]))
        {
            return;
        }

        if ((('\r' == tmp[0]) && ('\n' == tmp[1])
                && ('\r' == tmp[2]) && ('\n' == tmp[3]))
                ||
                (('\r' == tmp[0]) && ('\r' == tmp[1]))
                || (('\n' == tmp[0]) && ('\n' == tmp[1])))
        {
            return;    /* end of message */
        }

        if ((('\r' == tmp[0]) && ('\n' == tmp[1])
                && ((' ' == tmp[2]) || ('\t' == tmp[2])))
                ||
                (('\r' == tmp[0])
                 && ((' ' == tmp[1]) || ('\t' == tmp[1])))
                || (('\n' == tmp[0]) && ((' ' == tmp[1]) || ('\t' == tmp[1]))))
        {
            /* replace line end and TAB symbols by SP */
            tmp[0] = ' ';
            tmp[1] = ' ';
            tmp = tmp + 2;

            /* replace all following TAB symbols */
            for (; ('\t' == tmp[0] || ' ' == tmp[0]);)
            {
                tmp[0] = ' ';
                tmp++;
            }

            if ('\0' == tmp[0])
            {
                return;
            }
        }
    }
}

int stk_find_next_crlf(const char * start_of_header, const char ** end_of_header)
{
    const char *soh = start_of_header;

    *end_of_header = NULL;        /* AMD fix */


    /* VERIFY if TMP is the end of header or LWS.            */
    /* LWS are extra SP, HT, CR and LF contained in headers. */
    if ((' ' == soh[0]) || ('\t' == soh[0]))
    {
        // From now on, incoming message that potentially contains LWS must be processed with -> void osip_util_replace_all_lws(char *)
        // This is because the parser methods does not	support detection of LWS inside.
        return -1;
    }

    while (('\r' != *soh) && ('\n' != *soh))
    {
        if (*soh)
        {
            soh ++;
        }
        else
        {
            return -1;
        }
    }

    if (('\r' == soh[0]) && ('\n' == soh[1]))
    {
        // case 1: CRLF is the separator case 2 or 3: CR or LF is the separator
        soh = soh + 1;
    }

    *end_of_header = soh + 1;

    return 0;
}

/* this method search for the separator and   */
/* return it only if it is located before the */
/* second separator. */
char * stk_next_separator(const char *ch, int separator_osip_to_find, int before_separator)
{
    char *ind;
    char *tmp;

    ind = (char *)strchr (ch, separator_osip_to_find);

    if (ind == NULL)
    {
        return NULL;
    }

    tmp = NULL;

    if (before_separator != 0)
    {
        tmp = (char *)strchr (ch, before_separator);
    }

    if (tmp != NULL)
    {
        if (ind < tmp)
        {
            return ind;
        }
    }
    else
    {
        return ind;
    }

    return NULL;
}

char * stk_strnappend(char *dst, const char *src, size_t len)
{
    memmove ((void *) dst, (void *) src, len);
    dst += len;
    *dst = '\0';
    return dst;
}

char * stk_strappend(char *dst, const char *src)
{
    while (*src != '\0')
    {
        *dst = *src;
        src++;
        dst++;
    }

    *dst = '\0';
    return dst;
}

/* ---For better performance---
This is to replace this construction:
stk_strncpy (  dest, source, length);
stk_clrspace ( dest ); */
char * stk_clrncpy(char *dst, const char *src, size_t len)
{
    const char *pbeg;
    const char *pend;
    char *p;
    size_t spaceless_length;

    if (src == NULL)
    {
        return NULL;
    }

    /* find the start of relevant text */
    pbeg = src;

    while ((' ' == *pbeg) || ('\r' == *pbeg) || ('\n' == *pbeg) || ('\t' == *pbeg))
    {
        pbeg++;
    }


    /* find the end of relevant text */
    pend = src + len - 1;

    while ((' ' == *pend) || ('\r' == *pend) || ('\n' == *pend) || ('\t' == *pend))
    {
        pend--;

        if (pend < pbeg)
        {
            *dst = '\0';
            return dst;
        }
    }

    /* if pend == pbeg there is only one char to copy */
    spaceless_length = pend - pbeg + 1;   /* excluding any '\0' */
    memmove (dst, pbeg, spaceless_length);
    p = dst + spaceless_length;

    /* terminate the string and pad dest with zeros until len */
    do
    {
        *p = '\0';
        p++;
        spaceless_length++;
    }
    while (spaceless_length < len);

    return dst;
}

/* remove SPACE before and after the content */
int stk_clrspace(char *word)
{
    char *pbeg;
    char *pend;
    size_t len;

    if (word == NULL)
    {
        return -1;
    }

    if (*word == '\0')
    {
        return 0;
    }

    len = strlen (word);

    pbeg = word;

    while ((' ' == *pbeg) || ('\r' == *pbeg) || ('\n' == *pbeg) || ('\t' == *pbeg))
    {
        pbeg++;
    }

    pend = word + len - 1;

    while ((' ' == *pend) || ('\r' == *pend) || ('\n' == *pend) || ('\t' == *pend))
    {
        pend--;

        if (pend < pbeg)
        {
            *word = '\0';
            return 0;
        }
    }

    /* Add terminating NULL only if we've cleared room for it */
    if (pend + 1 <= word + (len - 1))
    {
        pend[1] = '\0';
    }

    if (pbeg != word)
    {
        memmove (word, pbeg, pend - pbeg + 2);
    }

    return 0;
}

/* remove " and SPACE before and after the content */
int stk_clrquote(char *word)
{
    char *pbeg;
    char *pend;
    size_t len;

    if (word == NULL)
    {
        return -1;
    }

    if (*word == '\0')
    {
        return 0;
    }

    len = strlen (word);

    pbeg = word;

    while (('"' == *pbeg) || (' ' == *pbeg) || ('\r' == *pbeg) || ('\n' == *pbeg) || ('\t' == *pbeg))
    {
        pbeg++;
    }

    pend = word + len - 1;

    while (('"' == *pend) || (' ' == *pend) || ('\r' == *pend) || ('\n' == *pend) || ('\t' == *pend))
    {
        pend--;

        if (pend < pbeg)
        {
            *word = '\0';
            return 0;
        }
    }

    /* Add terminating NULL only if we've cleared room for it */
    if (pend + 1 <= word + (len - 1))
    {
        pend[1] = '\0';
    }

    if (pbeg != word)
    {
        memmove (word, pbeg, pend - pbeg + 2);
    }

    return 0;
}

int stk_tolower(char *word)
{
    size_t i;
    size_t len = strlen(word);

    for (i = 0; i <= len - 1; i++)
    {
        if ('A' <= word[i] && word[i] <= 'Z')
        {
            word[i] = word[i] + 32;
        }
    }

    return 0;
}

/* in quoted-string, many characters can be escaped...   */
/* stk_quote_find returns the next quote that is not escaped */
char *	stk_quote_find(const char *qstring)
{
    char *quote;

    quote = (char *)strchr(qstring, '"');

    if (quote == qstring)         /* the first char matches and is not escaped... */
    {
        return quote;
    }

    if (quote == NULL)
    {
        return NULL;    /* no quote at all... */
    }

    /* this is now the nasty cases where '"' is escaped
    '" jonathan ros \\\""'
    |                  |
    '" jonathan ros \\"'
    |                |
    '" jonathan ros \""'
    |                |
    we must count the number of preceeding '\' */
    {
        int i = 1;

        for (;;)
        {
            if (0 == strncmp (quote - i, "\\", 1))
            {
                i++;
            }
            else
            {
                if (i % 2 == 1)     /* the '"' was not escaped */
                {
                    return quote;
                }

                /* else continue with the next '"' */
                quote = strchr (quote + 1, '"');

                if (quote == NULL)
                {
                    return NULL;
                }

                i = 1;
            }

            if (quote - i == qstring - 1)
                /* example: "\"john"  */
                /* example: "\\"jack" */
            {
                /* special case where the string start with '\' */
                if (*qstring == '\\')
                {
                    i++;    /* an escape char was not counted */
                }

                if (i % 2 == 0)     /* the '"' was not escaped */
                {
                    return quote;
                }
                else
                {
                    /* else continue with the next '"' */
                    qstring = quote + 1;    /* reset qstring because
											(*quote+1) may be also == to '\\' */
                    quote = strchr (quote + 1, '"');

                    if (quote == NULL)
                    {
                        return NULL;
                    }

                    i = 1;
                }

            }
        }

        return NULL;
    }
}

int stk_quoted_string_set(const char *name, const char *str, std::string &result, const char **next)
{
    *next = NULL;

    while ((' ' == *str) || ('\t' == *str) || (',' == *str))
    {
        if (*str)
        {
            str++;
        }
        else
        {
            return -1;    /* bad header format */
        }
    }

    if (strlen (str) <= strlen (name))
    {
        return -1;    /* bad header format... */
    }

    if (strncasecmp(name, str, strlen (name)) == 0)
    {
        const char *quote1;
        const char *quote2;
        const char *tmp;
        const char *hack = strchr (str, '=');

        if (hack == NULL)
        {
            return -1;
        }

        while (' ' == *(hack - 1))        /* get rid of extra spaces */
        {
            hack--;
        }

        if ((size_t) (hack - str) != strlen (name))
        {
            *next = str;
            return 0;
        }

        quote1 = stk_quote_find (str);

        if (quote1 == NULL)
        {
            return -1;    /* bad header format... */
        }

        quote2 = stk_quote_find (quote1 + 1);

        if (quote2 == NULL)
        {
            return -1;    /* bad header format... */
        }

        if (quote2 - quote1 == 1)
        {
            /* this is a special case! The quote contains nothing! */
            /* example:   Digest opaque="",cnonce=""               */
            /* in this case, we just forget the parameter... this  */
            /* this should prevent from user manipulating empty    */
            /* strings */
            tmp = quote2 + 1;     /* next element start here */

            for (; *tmp == ' ' || *tmp == '\t'; tmp++)
            {
            }

            for (; *tmp == '\n' || *tmp == '\r'; tmp++)
            {
            }                   /* skip LWS */

            *next = NULL;

            if (*tmp == '\0')     /* end of header detected */
            {
                return 0;
            }

            if (*tmp != '\t' && *tmp != ' ')
                /* LWS here ? */
            {
                *next = tmp;
            }
            else
            {
                /* it is: skip it... */
                for (; *tmp == ' ' || *tmp == '\t'; tmp++)
                {
                }

                if (*tmp == '\0') /* end of header detected */
                {
                    return 0;
                }

                *next = tmp;
            }

            return 0;
        }

        result.assign(quote1, quote2 - quote1 + 1);

        tmp = quote2 + 1;         /* next element start here */

        for (; *tmp == ' ' || *tmp == '\t'; tmp++)
        {
        }

        for (; *tmp == '\n' || *tmp == '\r'; tmp++)
        {
        }                       /* skip LWS */

        *next = NULL;

        if (*tmp == '\0')         /* end of header detected */
        {
            return 0;
        }

        if (*tmp != '\t' && *tmp != ' ')
            /* LWS here ? */
        {
            *next = tmp;
        }
        else
        {
            /* it is: skip it... */
            for (; *tmp == ' ' || *tmp == '\t'; tmp++)
            {
            }

            if (*tmp == '\0')     /* end of header detected */
            {
                return 0;
            }

            *next = tmp;
        }
    }
    else
    {
        *next = str;    /* wrong header asked! */
    }

    return 0;
}

void stk_uri_unescape(char *str)
{

}
